#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <assert.h>

//场景：
//1、屏蔽2号信号
//2、给进程发送2号信号，屏蔽2号信号，2号信号不会被递达，2号信号会一直在pending中
//3、获取进程的pending位图
//4、打印所有的pending位图中的信号

void PrintSig(sigset_t &pending)
{
    std::cout << "Pending bitmap: ";
    for (int signo = 31; signo > 0; signo--)
    {
        if (sigismember(&pending, signo))
        {
            std::cout << "1";
        }
        else
        {
            std::cout << "0";
        }
    }
    std::cout << std::endl;
}

void handler(int signum)
{
	//std::cout<<"递达中..."<<std::endl;		//不会打印是因为对信号进行屏蔽，不会被处理
	 sigset_t pending;
    sigemptyset(&pending);
    int n = sigpending(&pending); // 我正在处理2号信号哦！！
    assert(n == 0);

    // 3. 打印pending位图中的收到的信号
    std::cout << "递达中...: ";
    PrintSig(pending); 			// 结果：递达之前，pending 2号已经被清0
    std::cout << signum << " 号信号被递达处理..." << std::endl;
}

int main()
{
// 对2号信号进行自定义捕捉 --- 不让进程因为2号信号而终止
    signal(2, handler);

	//1、屏蔽2号信号
	sigset_t block,oblock;
	sigemptyset(&block);
	sigaddset(&block, 2);

	//如果我屏蔽了所有信号呢？？？
    // for(int signo = 1; signo <= 31; signo++) // 9， 19号信号无法被屏蔽， 18号信号会被做特殊处理
    //     sigaddset(&block, signo); // SIGINT --- 根本就没有设置进当前进程的PCB block位图中

	sigprocmask(SIG_BLOCK,&block,&oblock);		//第一个参数有三选项，SIG_BLOCK是添加进新的，SIG_UNBLOCK是解除，SIG_SETMASK是按照信号集设置
	std::cout<<"block signal 2 success..."<<std::endl;
	std::cout<<"PID: "<<getpid()<<std::endl;

	int cnt = 0;
	//3、获取进程的pending位图
	while(true)
	{
		sleep(1);
		sigset_t pending;
		sigemptyset(&pending);
		sigpending(&pending);		//输出型参数，输出挂起的信号

	//4、打印所有的pending位图中的信号
		PrintSig(pending);
		cnt++;

		if (cnt == 10)
        {
            std::cout << "解除对2号信号的屏蔽" << std::endl;
           	sigprocmask(SIG_UNBLOCK, &block, &oblock); // 2号信号会被 立即 递达, 默认处理是终止进程
           	sigprocmask(SIG_BLOCK, &block, &oblock); 
			cnt = 0;
        }
	}
	return 0;
}


//验证core dump位
// int main()
// {
// 	sigset_t s;		 // sigset_t是数据类型
// 	sigemptyset(&s); // 初始化，将所有信号从信号集中排空
// 	// sigfillset(&s);		//初始化，包含所有信号
// 	sigaddset(&s, 2); // 添加信号
// 	// sigdelset(&s,2);	//删除信号
// 	// sigismember(&s,2);	//查看信号集中有没有信号	返回1有，0无，-1error
// 	 pid_t id = fork();
// 	if(id == 0)
// 	{
// 	    sleep(2);
// 	    int a = 10;
// 	    a /= 0; // 故意异常，收到SIGFPE-> core
// 	    exit(0);
// 	}

// 	// father
// 	int status = 0;
// 	pid_t rid = waitpid(id, &status, 0);
// 	if(rid > 0)
// 	{
// 	    std::cout << "exit code: " << ((status>>8) & 0xFF) << std::endl; // 没有意义
// 	    std::cout << "exit signal: " << (status & 0x7F) << std::endl;
// 	    std::cout << "core dump: " << ((status>>7) & 0x1) << std::endl;
// 	}

// 	// std::cout << "run begin ..." << std::endl;
// 	// int a = 10;
// 	// a /= 0; // SIGFPE -> Core

// 	// std::cout << "run end ..." << std::endl;

// 	//while(true) sleep(1);
// 	return 0;
// }